/**
 * @author nttdocomo
 */
define(function(require) {
	require("../../aries");
	require("./base");
	require("./vtypes");
	/**
	 Creates a new form field base.
	 @class Represents a field of basic.
	 @param {Object} options
	 */
	aries.klass("aries.form.field.Text", aries.form.field.Base.extend({
		/**
		 * @cfg {String} minLengthText
		 * Error text to display if the **{@link #minLength minimum length}** validation fails.
		 */
		//<locale>
		minLengthText : 'The minimum length for this field is {0}',
		//</locale>

		/**
		 * @cfg {Boolean} [selectOnFocus=false]
		 * true to automatically select any existing field text when the field receives input focus
		 */

		/**
		 * @cfg {Boolean} allowBlank
		 * Specify false to validate that the value's length is > 0
		 */
		allowBlank : true,

		/**
		 * @cfg {String} blankText
		 * The error text to display if the **{@link #allowBlank}** validation fails
		 */
		//<locale>
		blankText : 'This field is required',
		/**
		 * @cfg {Number} minLength
		 * Minimum input field length required
		 */
		minLength : 0,

		applyEmptyText : function() {
			var me = this, emptyText = me.emptyText, isEmpty;

			if (me.rendered && emptyText) {
				isEmpty = me.getRawValue().length < 1 && !me.hasFocus;

				if (Ext.supports.Placeholder) {
					me.inputEl.dom.placeholder = emptyText;
				} else if (isEmpty) {
					me.setRawValue(emptyText);
				}

				//all browsers need this because of a styling issue with chrome + placeholders.
				//the text isnt vertically aligned when empty (and using the placeholder)
				if (isEmpty) {
					me.inputEl.addCls(me.emptyCls);
				}

				me.autoSize();
			}
		},
		initialize : function(options) {
			options = $.extend({
				emptyCls : aries.baseCSSPrefix + 'form-empty-field'
			}, options);
			aries.form.field.Base.prototype.initialize.apply(this, arguments);
		},

		/**
		 * Validates a value according to the field's validation rules and returns an array of errors
		 * for any failing validations. Validation rules are processed in the following order:
		 *
		 * 1. **Field specific validator**
		 *
		 *     A validator offers a way to customize and reuse a validation specification.
		 *     If a field is configured with a `{@link #validator}`
		 *     function, it will be passed the current field value.  The `{@link #validator}`
		 *     function is expected to return either:
		 *
		 *     - Boolean `true`  if the value is valid (validation continues).
		 *     - a String to represent the invalid message if invalid (validation halts).
		 *
		 * 2. **Basic Validation**
		 *
		 *     If the `{@link #validator}` has not halted validation,
		 *     basic validation proceeds as follows:
		 *
		 *     - `{@link #allowBlank}` : (Invalid message = `{@link #emptyText}`)
		 *
		 *         Depending on the configuration of `{@link #allowBlank}`, a
		 *         blank field will cause validation to halt at this step and return
		 *         Boolean true or false accordingly.
		 *
		 *     - `{@link #minLength}` : (Invalid message = `{@link #minLengthText}`)
		 *
		 *         If the passed value does not satisfy the `{@link #minLength}`
		 *         specified, validation halts.
		 *
		 *     -  `{@link #maxLength}` : (Invalid message = `{@link #maxLengthText}`)
		 *
		 *         If the passed value does not satisfy the `{@link #maxLength}`
		 *         specified, validation halts.
		 *
		 * 3. **Preconfigured Validation Types (VTypes)**
		 *
		 *     If none of the prior validation steps halts validation, a field
		 *     configured with a `{@link #vtype}` will utilize the
		 *     corresponding {@link Ext.form.field.VTypes VTypes} validation function.
		 *     If invalid, either the field's `{@link #vtypeText}` or
		 *     the VTypes vtype Text property will be used for the invalid message.
		 *     Keystrokes on the field will be filtered according to the VTypes
		 *     vtype Mask property.
		 *
		 * 4. **Field specific regex test**
		 *
		 *     If none of the prior validation steps halts validation, a field's
		 *     configured `{@link #regex}` test will be processed.
		 *     The invalid message for this test is configured with `{@link #regexText}`
		 *
		 * @param {Object} value The value to validate. The processed raw value will be used if nothing is passed.
		 * @return {String[]} Array of any validation errors
		 */
		getErrors : function(value) {
			var me = this, errors = aries.form.field.Base.prototype.getErrors.apply(this, arguments), validator = this.validator, emptyText = this.emptyText, allowBlank = this.allowBlank, vtype = this.vtype, vtypes = aries.form.field.Vtypes, regex = this.regex, format = aries.String.format, msg;

			value = value || this.processRawValue(this.getRawValue());

			if ($.isFunction(validator)) {
				msg = validator.call(this, value);
				if (msg !== true) {
					errors.push(msg);
				}
			}

			if (value.length < 1 || value === emptyText) {
				if (!allowBlank) {
					errors.push(me.blankText);
				}
				//if value is blank, there cannot be any additional errors
				return errors;
			}

			if (value.length < me.minLength) {
				errors.push(format(me.minLengthText, me.minLength));
			}

			if (value.length > me.maxLength) {
				errors.push(format(me.maxLengthText, me.maxLength));
			}

			if (vtype) {
				if (!vtypes[vtype](value, me)) {
					errors.push(me.vtypeText || vtypes[vtype + 'Text']);
				}
			}

			if (regex && !regex.test(value)) {
				errors.push(me.regexText || me.invalidText);
			}

			return errors;
		},

		onFocus : function() {
			var me = this;
			aries.form.field.Base.prototype.onFocus.apply(this, arguments);
			if (me.emptyText) {
				me.autoSize();
			}
		},

		/**
		 * Returns the raw String value of the field, without performing any normalization, conversion, or validation. Gets
		 * the current value of the input element if the field has been rendered, ignoring the value if it is the
		 * {@link #emptyText}. To get a normalized and converted value see {@link #getValue}.
		 * @return {String} The raw String value of the field
		 */
		getRawValue : function() {
			var v = aries.form.field.Base.prototype.getRawValue.apply(this, arguments);
			if (v === this.emptyText) {
				v = '';
			}
			return v;
		},

		// private
		postBlur : function() {
			//this.callParent(arguments);
			this.applyEmptyText();
		},

		// private
		preFocus : function() {
			var me = this, inputEl = me.inputEl, emptyText = me.emptyText, isEmpty;
			if (emptyText && !$.support.placeholder && inputEl.dom.value === emptyText) {
				me.setRawValue('');
				isEmpty = true;
				inputEl.removeClass(me.emptyCls);
			} else if ($.support.placeholder) {
				me.inputEl.removeClass(me.emptyCls);
			}
			if (me.selectOnFocus || isEmpty) {
				inputEl.dom.select();
			}
		},

		/**
		 * Performs any necessary manipulation of a raw String value to prepare it for conversion and/or
		 * {@link #validate validation}. For text fields this applies the configured {@link #stripCharsRe}
		 * to the raw value.
		 * @param {String} value The unprocessed string value
		 * @return {String} The processed string value
		 */
		processRawValue : function(value) {
			var stripRe = this.stripCharsRe, newValue;

			if (stripRe) {
				newValue = value.replace(stripRe, '');
				if (newValue !== value) {
					this.setRawValue(newValue);
					value = newValue;
				}
			}
			return value;
		}
	}))
});
